package com.hw.protocol.tool.decode;

import com.hw.protocol.tool.config.DecodeContext;
import com.hw.protocol.tool.model.Result;
import com.hw.protocol.tool.model.entity.JkProtocol;
import com.hw.protocol.tool.util.CrcUtil;
import com.hw.protocol.tool.util.CryptoUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author : lihy
 * @date : 2024/3/15 14:22
 * description:
 */
@Slf4j
@Component
public class JkDecode implements IDecode {

    @Override
    public Result decode(byte[] bytes) {
        ByteBuf in = wrapBytes(bytes);
        byte fh = in.getByte(0);
        if (fh != (byte) 0x68) {
            in.release();
            return Result.error("帧头错误");
        }
        JkProtocol protocol = new JkProtocol();

        protocol.setType(in.getByte(1));
        protocol.setVersion(in.getByte(2));
        protocol.setLength(in.getShort(3));
        protocol.setSeq(in.getByte(5));
        protocol.setCmd(in.getByte(6));
        byte[] data = new byte[protocol.getLength() - 10];
        in.getBytes(7, data);
        Result decryptResult = decrypt(data);
        if(decryptResult.getCode()==200) {
            protocol.setData((byte[])decryptResult.getData());
        }else{
            in.release();
            return decryptResult;
        }

        byte[] noCrc = new byte[protocol.getLength() - 8];
        in.getBytes(5, noCrc);
        //CRC
        byte[] crcBytes = new byte[2];
        in.getBytes(protocol.getLength() - 3, crcBytes);
        protocol.setCrc(crcBytes);
        if (!CrcUtil.chechCrc16Xmodem(noCrc, false, crcBytes)) {
            in.release();
            return Result.error("crc验证错误");
        }
        in.release();
        return Result.success(protocol);
    }

    /**
     * 数据解密
     * @param data
     * @return
     */
    private Result decrypt(byte[] data){
        ByteBuf dataBuf = Unpooled.wrappedBuffer(data);
        try {
            //未解密数据
            byte[] encryptData = new byte[dataBuf.capacity() - 4 - 32];
            dataBuf.getBytes(4, encryptData);
            //mac
            byte[] mac = new byte[32];
            dataBuf.getBytes(dataBuf.capacity() - 32, mac);
            //计算出的mac
            byte[] macKey = CrcUtil.convert16HexToByte(DecodeContext.jkMackey.replace(" ", ""));
            byte[] calMac = CryptoUtil.hMacSha256(encryptData, macKey);
            if (!Arrays.equals(mac, calMac)) {
                dataBuf.release();
                return Result.error("数据mac不匹配");
            }
            //解码后的数据
            byte[] sessionKey = CrcUtil.convert16HexToByte(DecodeContext.jkSessionkey.replace(" ", ""));
            byte[] decryptData = CryptoUtil.decrypt(encryptData, sessionKey);
            return Result.success(decryptData);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            dataBuf.release();
            return Result.error("解密失败");
        }
    }
}
